import java.util.HashMap;

public class CalcFuncs{
  public static HashMap<String, Object> vars =
    new HashMap<String, Object>();

  public static void usage(){
    Calc.puts("Using Calc:");
    Calc.puts("  This is (to some degree) a postfix lisp. data and " +
              "functions alike are pushed to the stack, and then " +
              "the stack is simplified.");
  }

  // Replace :vars with values if they exist
  public static Object check(Object in, Class wanted){
    if (in.getClass() != wanted){
      if (in.getClass() == "".getClass())
        return get((String)in);
      throw new RuntimeException("Parameter isn't loved.");
    }
    return in;
  }

  // The "four" operators
  public static ILN plus(ILN one, ILN two){
    return one.plus(two);
  }
  public static ILN minus(ILN one, ILN two){
    return one.minus(two);
  }
  public static ILN times(ILN one, ILN two){
    return one.times(two);
  }
  public static ILN over(ILN one, ILN two)
  {
    int length = ((ILN)get(":round-length")).toInt();
    return one.over(two, length);
  }

  // Basic math
  public static ILN square(ILN one){
    return one.times(one);
  }
  public static ILN modulo(ILN one, ILN two){
    int length = ((ILN)get(":round-length")).toInt();
    return one.minus(one.over(two, length).ipart().times(two));
  }

  // Convert a number to a string in a different base
  public static CalcString convert(ILN base, ILN num){
    if (base.cmp(ILN.neu("36")) == -1 ||
        base.cmp(ILN.neu("2"))  == 1)
      throw new RuntimeException("That base is too large/small!");
    int length = ((ILN)get(":round-length")).toInt();

    return new CalcString(num.toString(base.toInt(), length));
  }

  // Basic stack/variable manipulation
  public static void pop(Object one){
  }
  public static void set(String var, Object val){
    vars.put(var, val);
  }
  public static Object get(String var){
    return vars.get(var);
  }
  public static void del(String var){
    vars.remove(var);
  }
  public static CalcBool has(String var){
    return new CalcBool(vars.containsKey(var));
  }

  // Boolean math
  public static CalcBool and(CalcBool one, CalcBool two){
    return new CalcBool(one.bool && two.bool);
  }
  public static CalcBool or(CalcBool one, CalcBool two){
    return new CalcBool(one.bool || two.bool);
  }
  public static CalcBool xor(CalcBool one, CalcBool two){
    return new CalcBool(one.bool ^ two.bool);
  }
  public static CalcBool not(CalcBool one){
    return new CalcBool(!one.bool);
  }

  // String operations
  public static ILN strstr(CalcString haystack, CalcString needle){
    return ILN.neu("" + haystack.str.indexOf(needle.str));
  }
  public static ILN strlen(CalcString blah){
    return ILN.neu("" + blah.str.length());
  }
  public static CalcBool matches(CalcString str, CalcString regex){
    return new CalcBool(str.str.matches(regex.str));
  }
  public static CalcString replace(CalcString start, CalcString from,
      CalcString to){
    return new CalcString(start.str.replace(from.str, to.str));
  }
  public static CalcString substring(CalcString blah, ILN from, ILN to){
    int fr = from.toInt(), t = to.toInt();
    return new CalcString(blah.str.substring(fr, t));
  }

  // Basic trinary operator
  public static Object iff(CalcBool cond, Object a, Object b){
    if (cond.bool) return a; return b;
  }
  
  // Variable comparison
  public static CalcBool equals(Object a, Object b){
    return new CalcBool(a.equals(b)); }

  // Output functions
  public static void puts(CalcString foo){
    Calc.puts(foo.str); }
  public static void puts(Object foo){
    Calc.puts("" + foo); }
}
